﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VideoReflector.Models;
using VideoReflector.Views;
using VideoReflector.Video;

namespace VideoReflector.Controllers
{
    /// <summary>
    /// Controller tasked with managing export of session video clips to file
    /// </summary>
    public class ClipExporterController : TaskController
    {
        #region Private fields

        private IClipStreamer _clipExporter;
        private IList<ClipTag> _clipTags;
        private VideoFileType _sessionVideoFile;
        private string _sessionFileDirectory;
        private string _outputPath;

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor for ClipExporterController object
        /// </summary>
        /// <param name="clipTags"> Collection of ClipTag objects which correspond to the clips to be exported </param>
        /// <param name="sessionVideo"> Object containing details of video file associated with session </param>
        /// <param name="sessionFileDirectory"> Directory where session files are contained in on disk </param>
        public ClipExporterController(IList<ClipTag> clipTags, VideoFileType sessionVideoFile, string sessionFileDirectory)
        {
            _clipTags = clipTags;
            _sessionVideoFile = sessionVideoFile;
            _sessionFileDirectory = sessionFileDirectory;
        }

        #endregion // Constructor

        #region Public properties

        /// <summary>
        /// Output path of file clips will be exported to
        /// </summary>
        public string OutputPath
        {
            get 
            { 
                return _outputPath;  
            }
            set 
            { 
                _outputPath = value;
                NotifyPropertyChanged("OutputPath");
            }
        }

        /// <summary>
        /// Current progress of clip export in terms of number of clips exported so far
        /// </summary>
        public int ExportProgress
        {
            get 
            {
                if (_clipExporter != null)
                    return _clipExporter.ClipNumber + 1;
                else
                    return 0;
            }
        }

        /// <summary>
        /// Maximum value for ExportProgress counter (i.e. number of clips being exported)
        /// </summary>
        public int ExportProgressMax
        {
            get { return _clipTags.Count; }
        }

        #endregion // Public properties

        #region Commands

        #region Start Export

        private RelayCommand _startExportCommand;

        /// <summary>
        /// Begin writing clips to disk and attach events to update export progress and raise Finish event 
        /// when export is complete
        /// </summary>
        public ICommand StartExportCommand
        {
            get
            {
                if (_startExportCommand == null)
                {
                    _startExportCommand = new RelayCommand
                    (
                        param => this.StartExport(),
                        param => this.CanStartExport()
                    );
                }
                return _startExportCommand;
            }
        }

        private void StartExport() 
        {
            _clipExporter = new VlcClipExporter(_clipTags, _sessionVideoFile, _sessionFileDirectory, OutputPath);
            _clipExporter.PropertyChanged += (s, e) => 
            {
                // update export progress on moving to new clip
                if (e.PropertyName == "ClipNumber")
                {
                    NotifyPropertyChanged("ExportProgress");
                }
                // if streamer no longer 'playing' and progress counter equals tag count, raise finished event
                else if (e.PropertyName == "IsPlaying" && _clipExporter.IsPlaying == false 
                    && ExportProgress == _clipTags.Count)
                {
                    _clipExporter.Dispose();
                    OnFinished(new TaskFinishedEventArgs(false));
                }
            };
            _clipExporter.Play();
        }

        private bool CanStartExport()
        {
            return !String.IsNullOrEmpty(OutputPath)
                && Directory.Exists(Path.GetDirectoryName(OutputPath))
                && _clipExporter == null;
        }

        #endregion // Start Export

        #region Cancel Export

        private RelayCommand _cancelExportCommand;

        /// <summary>
        /// Cancel current clip export, deleting clip output file if present
        /// </summary>
        public ICommand CancelExportCommand
        {
            get
            {
                if (_cancelExportCommand == null)
                {
                    _cancelExportCommand = new RelayCommand
                    (
                        param => this.CancelExport(),
                        param => this.CanCancelExport()
                    );
                }
                return _cancelExportCommand;
            }
        }

        private void CancelExport()
        {
            if (_clipExporter != null && _clipExporter.IsPlaying)
            {
                _clipExporter.Stop();
                _clipExporter.Dispose();
            }
            if (File.Exists(OutputPath))
            {
                try
                {
                    File.Delete(OutputPath);
                }
                catch (IOException)
                {
                    MessageBox.Show("Sorry clip file " + OutputPath + 
                        " could not be deleted and will have to be removed manually.", "File not deleted", 
                        MessageBoxButton.OK, MessageBoxImage.Warning);
                }
            }
            OnFinished(new TaskFinishedEventArgs(true));
        }

        private bool CanCancelExport()
        {
            return true;
        }

        #endregion

        #region Output Path Browse

        private RelayCommand _outputPathBrowseCommand;

        /// <summary>
        /// Show a file browser dialog to select the output path to save the exported clips file to
        /// </summary>
        public ICommand OutputPathBrowseCommand
        {
            get
            {
                if (_outputPathBrowseCommand == null)
                {
                    _outputPathBrowseCommand = new RelayCommand
                    (
                        param => this.OutputPathBrowse(),
                        param => this.CanOutputPathBrowse()
                    );
                }
                return _outputPathBrowseCommand;
            }
        }

        private void OutputPathBrowse()
        {
            var saveDialog = new Microsoft.Win32.SaveFileDialog();
            saveDialog.Title = "Choose clip export video file output path";
            string videoFileExt = Path.GetExtension(_sessionVideoFile.Location.Value).Substring(1);
            saveDialog.Filter = String.Format("Video file (.{0})|*.{0}", videoFileExt);
            saveDialog.FileName = Path.GetFileNameWithoutExtension(_sessionVideoFile.Location.Value) + "_Clips";
            saveDialog.InitialDirectory = _sessionFileDirectory;
            saveDialog.ValidateNames = true;
            saveDialog.CheckPathExists = true;
            if (saveDialog.ShowDialog() == true)
            {
                OutputPath = saveDialog.FileName;
            }
        }

        private bool CanOutputPathBrowse()
        {
            return _clipExporter == null
                || !_clipExporter.IsPlaying;
        }

        #endregion // Output Path Browse

        #endregion // Commands

    }
}
